package org.wevil.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数字操作工具类
 * */
public class NumberUtil {

    private static List<String> specialStrList = new ArrayList<>();

    private static Pattern pattern = Pattern.compile("\\pP");

    static{
        specialStrList.add("0");
        specialStrList.add("0.0");
        specialStrList.add("0.00");
    }

    // ============================ 格式化 =======================================================//

    /**
     * 格式化数字。进位方式为四舍五入
     *
     * @param numberStr 要格式化的数字字符串
     * @param scale 保留几位小数。默认2位
     * @param rightZero 是要要保留小数后的0。默认保留
     * @param comma 千分位是否加逗号。默认加
     * */
    public static String format(
            String numberStr,
            Integer scale,
            Boolean rightZero,
            Boolean comma
    ){
        Number number = parseNumber(numberStr);
        if(number != null){
            return format(number, scale, rightZero, comma);
        }
        return "";
    }

    /**
     * 格式化数字。进位方式为四舍五入
     *
     * @param number 要格式化的数字字符串
     * @param scale 保留几位小数。默认2位
     * @param rightZero 是要要保留小数后的0。默认保留
     * @param comma 千分位是否加逗号。默认加
     * */
    public static String format(
            Number number,
            Integer scale,
            Boolean rightZero,
            Boolean comma
    ){
        if(number == null){
            number = 0;
        }
        // 初始化默认值
        scale = scale == null ? 2 : scale;
        rightZero = rightZero == null || rightZero;
        comma = comma == null || comma;
        // 根据保留几位小数生成格式化表达式
        StringBuilder pattern = new StringBuilder("#0");
        if(comma){
            pattern = new StringBuilder("###,##0");
        }
        if(scale>=1){
            pattern.append(".");
        }
        for(int i=1; i<=scale; i++){
            if(rightZero){
                pattern.append("0"); // 保留0
            }
            else{
                pattern.append("#"); // 不保留0
            }
        }
        // 格式化数字
        DecimalFormat dFormat = new DecimalFormat(pattern.toString());
        dFormat.setRoundingMode(RoundingMode.HALF_UP); //四舍五入
        return dFormat.format(number);
    }

    // ============================ 转换 =======================================================//

    /**
     * 数字转金额中文
     *
     * @author wanglei
     * @since 2023-11-23
     */
    public static String convertChinese(BigDecimal money){
        BigDecimal moneyNew = money;
        String resultStr = "";
        if(money.compareTo(BigDecimal.ZERO) < 0){
            moneyNew = money.negate();
        }
        String[] upNum = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
        String[] danwei = {"圆","拾","佰","仟","万","拾","佰","仟","亿","拾","佰","仟"};
        //取消科学记数法
        NumberFormat numFormat = NumberFormat.getInstance();
        numFormat.setMaximumFractionDigits(2);//设置小数位个数
        numFormat.setGroupingUsed(false);//取消科学技术发
        String formatNum = numFormat.format(moneyNew);
        String strmoney = formatNum + "";//浮点型转为字符型
        String lastUpNum = "null"; //用于存放上个参数的值
        String result = "";//返回的结果
        String[] split = strmoney.split("\\.");
        String strMoney = split[0];
        String point = "";
        //小数部分取值处理。
        if(split.length>1){
            point = split[1];
            if(point.length()==1){
                point = point.concat("0");
            }
        }else {
            point = "0";
        }
        //大于12位就直接返回。
        int moneyLen = strMoney.length();
        if(moneyNew.compareTo(BigDecimal.ZERO) == 0){
            return "零圆整";
        }
        if(moneyLen>12){
            return "金额："+moneyNew+"元，超出大写转换范围。最大金额：999999999999.99元";
        }
        //整数(integer)部分处理。
        if(!"0".equals(strMoney)){
            for (int i = 0; i < moneyLen; i++) {
                String strNum = strMoney.charAt(i)+"";
                int singleNum = Integer.parseInt(strNum);
                String upSingleNum = upNum[singleNum];
                //上一为不等于0的情况
                if(!"零".equals(lastUpNum)){
                    if(!"零".equals(upSingleNum)){
                        result = result.concat(upSingleNum).concat(danwei[moneyLen-i-1]);
                    }else
                        //为零但是在万、亿位上要加单位 (moneyLen-i)==9 指的是单位：亿。  (moneyLen-i)==5指的是单位：万
                        if( (moneyLen-i)==5 || (moneyLen-i)==9 ){
                            lastUpNum="";
                        }else {
                            result=result.concat(upSingleNum);
                        }
                }
                //上一位为0的情况
                if("零".equals(lastUpNum) && !"零".equals(upSingleNum)){
                    result = result.concat(upSingleNum).concat(danwei[moneyLen-i-1]);
                }
                //捕捉上一位数（lastUpNum）为零的情况做优化。
                if((moneyLen-i)==5 || (moneyLen-i)==9 ){
                    //排除加单位时前面为"零"的情况。如：两百零万
                    if("零".equals(lastUpNum)||"null".equals(lastUpNum)){
                        result = result.substring(0,result.length()-1);
                    }
                    if(!result.endsWith("亿")){
                        result = result.concat(danwei[moneyLen-i-1]);
                    }
                    lastUpNum="";
                }else {
                    //把当前大写数字复制给 lastUpNum 用于下次判断
                    lastUpNum = upSingleNum;
                }
            }
            //对几万元整和几亿元整(result:五万零或者五亿零零)做优化。
            result=result.replaceAll("零零","零");
            if(result.endsWith("零")){
                String substring = result.substring(0,result.length() - 1);
                result = substring;
            }
            result = result.concat("圆");
            result = result.replaceAll("圆圆","圆");
            result = result.replaceAll("万万","万");

        }

        //小数(point)部分处理
        if("0".equals(point)){
            result =  result+"整";
        }else {
            if((point.charAt(0)+"").equals("0")){
                result = result.concat(upNum[Integer.parseInt(point.charAt(1)+"")]+"分");
            }else if((point.charAt(1)+"").equals("0")){
                result = result.concat(upNum[Integer.parseInt(point.charAt(0)+"")]+"角");
            }else {
                result = result.concat(upNum[Integer.parseInt(point.charAt(0)+"")]+"角").concat(upNum[Integer.parseInt(point.charAt(1)+"")]+"分");
            }
        }
        if(money.compareTo(BigDecimal.ZERO) < 0){
            resultStr = "负"+ result;
            return resultStr;
        }else {
            return result;
        }
    }

    /**
     * 将带”E“的数据。例如”6.0E9“转换为正常数据
     *
     * @author wanglei
     * @since 2021/6/25
     * */
    public static String number2Plain(String str){
        return new BigDecimal(str).toPlainString();
    }

    /**
     * 数字后面去零
     *
     * @author wanglei
     * @since 2021/11/29
     * */
    public static String deleteZeroAfter(String str){
        int strLen = str.length();
        String result = str;
        for(int i=strLen-1; i>0; i--){
            String temp = result.substring(result.length()-1);
            if(temp.equals("0")){
                result = result.substring(0, i);
            }
        }
        return result;
    }

    /**
     * 数字前面补零
     *
     * @author wanglei
     * @since 2021/4/29
     * */
    public static String addZeroForNum(String str, int strLength) {
        int strLen = str.length();
        StringBuilder sb;
        while (strLen < strLength) {
            sb = new StringBuilder();
            sb.append("0").append(str);// 左补0
            str = sb.toString();
            strLen = str.length();
        }
        return str;
    }

    /**
     * 格式化金额为两位小数
     * */
    public static BigDecimal formatBigDecimal(BigDecimal value){
        DecimalFormat dFormat = new DecimalFormat("#.00");
        String format = dFormat.format(value);
        return new BigDecimal(format);
    }

    /**
     * 格式化数字，不保留0，如果为空返回0
     * @param str 数字的字符串
     * @return 不保留0的数字字符串，比如2.30返回 2.3
     * */
    public static String formatNumberNoZero(String str){
        return formatNumberWithFormat(str, "#.##");
    }

    /**
     * 格式化数字，可以指定格式化模板，例如 #.##，#.00
     * #.##,不保留0，比如0.10，返回0.1
     * #.00，保留0，比如0.1，返回0.10
     * @param str 要格式化的数字
     * @param format 格式化模板
     * @return 格式化好的数字字符串
     * */
    public static String formatNumberWithFormat(String str, String format){
        if(str != null){
            str = str.trim();
            for(String specialStr : specialStrList){
                if(specialStr.equals(str)){
                    return "0";
                }
            }
            if(isNumeric(str)){
                // 如果是05这样的数字，直接返回。
                if(isPrefixWithZero(str)){
                    return str;
                }
                DecimalFormat dFormat = new DecimalFormat(format);
                dFormat.setRoundingMode(RoundingMode.HALF_UP);//四舍五入必须加这段
                String formatStr = dFormat.format(new BigDecimal(str));
                return new BigDecimal(formatStr).toString();
            }
            return str;
        }else{
            return "0";
        }
    }

    /**
     * 判断前缀为0的数字，比如001，02，03这样的
     * @param str 数字字符串
     * @return true：是前缀带0的字符串，false：不是前缀带0的字符串
     * */
    public static boolean isPrefixWithZero(String str){
        str = str.trim();
        if(str.length()>0){
            if(isNumeric(str)){
                if(str.length()>=2){
                    String sub1 = str.substring(0,1);
                    String sub2 = str.substring(1,2);
                    // 判断逻辑：第一位是0，第二位不是.的数字，长度要大于等于2
                    return sub1.equals("0") && !sub2.equals(".");
                }
            }
        }
        return false;
    }

    /**
     * 去除数字后面无用的零
     * */
    public static String removeEndZero(double value){
        NumberFormat nf = NumberFormat.getInstance();
        return nf.format(value);
    }

    /**
     * 格式化金额显示 小数点后面的0删除掉
     * @param bigDecimal 金额bigDecimal
     */
    public static String formatMoneyZeroTrim(BigDecimal bigDecimal){
        if (bigDecimal==null){
            return "0";
        }
        DecimalFormat decimalFormat = new DecimalFormat("###,##0.00");
        String res = decimalFormat.format(bigDecimal).replace(".00","");
        if (res.contains(".")){
            res = trimRight(res,"0");
        }
        return res == null || res.isEmpty() ? "0" : res;
    }

    /**
     * 格式化金额显示，不去除小数点
     * @param bigDecimal 金额bigDecimal
     */
    public static String formatMoneyStr(BigDecimal bigDecimal){
        if (bigDecimal==null){
            return "0.00";
        }
        DecimalFormat decimalFormat = new DecimalFormat("###,##0.00");
        String res = decimalFormat.format(bigDecimal);
        return res.isEmpty() ? "0.00" : res;
    }

    /**
     * 删除左边字符
     * @param param 参数
     * @param target 要删除的字符
     * @return
     */
    public static String trimLeft(String param,String target){
        if (param != null && target != null && !"".equals(target)){
            while (param.startsWith(target)){
                param = param.replaceFirst(target,"");
            }
        }
        return param;
    }

    /**
     * 循环删除右边指定字符
     * @param param 输入
     * @param target 删除目标
     */
    public static String trimRight(String param,String target){
        if (param != null && target != null && !target.isEmpty()){
            while (param.endsWith(target)){
                param = param.substring(0,param.length() - target.length());
            }
        }
        return param;
    }

    /**
     * 删除 右边的标点符号
     * @param param 原字符串
     * @return
     */
    public static String trimRightSymbol(String param){
        if (param == null || "".equals(param)){
            return "";
        }
        char c[] = param.toCharArray();
        int count = 0;
        for (int i = c.length-1; i >= 0; i--) {
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                count++;
            }else {
                break;
            }
        }
        if (count == c.length){
            return "";
        }
        if (count > 0){
            return param.substring(0,param.length() - count);
        }
        return param;
    }

    /**
     * 删除两边的标点符号
     * @param param 输入字符串
     * @param ignore 忽略的标点符号
     * @return
     */
    public static String trimSymbol(String param,String... ignore){
        if (param == null || "".equals(param)){
            return "";
        }
        param = param.trim();
        char c[] = param.toCharArray();
        int start = 0;
        int end = c.length;
        HashSet<String> set = new HashSet<>();
        set.addAll(Arrays.asList(ignore));
        for (int i = c.length-1; i >= 0; i--) {
            if (set.contains(String.valueOf(c[i]))) {
                break;
            }
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                end --;
            }else {
                break;
            }
        }
        for (int i = 0; i < c.length; i++) {
            if (set.contains(String.valueOf(c[i]))) {
                break;
            }
            Matcher matcher = pattern.matcher(String.valueOf(c[i]));
            if (matcher.matches()) {
                start ++;
            }else {
                break;
            }
        }
        if (start < end){
            return param.substring(start,end);
        }else {
            return  "";
        }
    }

    /**
     * 字符串格式化为金额格式
     * @param string
     * @return
     */
    public static String formatMoneyByString(String string){
        BigDecimal bigDecimal = null;
        if (isNumeric(string)){
            bigDecimal = new BigDecimal(string);
        }
        return formatMoneyZeroTrim(bigDecimal);
    }

    /**
     * BigDecimal的除法, decimal 是保留几位小数
     * */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int decimal){
        return a.divide(b, decimal, RoundingMode.HALF_UP);
    }

    /**
     * 利用正则表达式判断字符串是否是数字
     * @param str 数字字符串
     * @return true：是数字，false：不是数字
     * */
    public static boolean isNumeric(String str){
        if(str!=null && str.trim().length()>0){
            // 清除两边空格
            str = str.trim();
            // 清除货币里的逗号
            str = str.replace(",", "");
            return Pattern.matches("(-?\\d+(\\.\\d+)?)", str);
        }
        return false;
    }

    /**
     * 利用正则表达式判断字符串是否是数字
     * @param str 数字字符串
     * @param endWithDot 结尾是.算不算数组。true：是，false，不是
     * @return true：是数字，false：不是数字
     * */
    public static boolean isNumeric(String str, boolean endWithDot){
        if(str!=null && str.trim().length()>0){
            // 清除两边空格
            str = str.trim();
            // 清除货币里的逗号
            str = str.replace(",", "");
            if(endWithDot){
                return Pattern.matches("(-?\\d+(\\.\\d*)?)", str);
            }
            return Pattern.matches("(-?\\d+(\\.\\d+)?)", str);
        }
        return false;
    }

    /**
     * BigDecimal的减法，
     * @param minuend 被减数
     * @param subtract 减数
     * @return
     */
    public static BigDecimal subtraction(BigDecimal minuend, BigDecimal subtract){
        return minuend.subtract(subtract);
    }

    /**
     * 小数转换为百分比
     * */
    public static String decimal2Percent(BigDecimal decimal){
        BigDecimal value = formatBigDecimal(decimal.multiply(new BigDecimal(100)));
        if (value.toString().equals("0.00")){
            return "0%";
        }
        String temp = trimRight(trimRight(value.toString(),"0"),".");
        return temp + "%";
    }

    /**
     * 判断是否奇数
     * */
    public static boolean isOdd(int a){
        return a % 2 == 1;
    }

    /**
     * 判断字符串是否为数字类型，并转换为Number对象
     * @param str 待判断的字符串
     * @return 如果是数字则返回对应的Number对象，否则返回null
     */
    public static Number parseNumber(String str) {
        if (str == null || str.trim().isEmpty()) {
            return null;
        }

        // 尝试转换为整数
        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException e1) {
            // 尝试转换为长整数
            try {
                return Long.parseLong(str);
            } catch (NumberFormatException e2) {
                // 尝试转换为浮点数
                try {
                    return Double.parseDouble(str);
                } catch (NumberFormatException e3) {
                    // 尝试转换为BigDecimal（支持更大范围的数字）
                    try {
                        return new BigDecimal(str);
                    } catch (NumberFormatException e4) {
                        // 所有转换都失败，不是数字
                        return null;
                    }
                }
            }
        }
    }
}
